﻿using Tszy.Unlimited.Base.Common;

namespace Tszy.Examples.FSM;

public class State
{
    public virtual long Identity { get; set; }
    public StateMachine? OwnerStateMachine { get; set; }
    public bool CanEnterState { get; } = true;
    public bool CanExitState { get; } = true;
    public virtual void OnEnter() { }
    public virtual void OnUpdate() { }
    public virtual void OnExit() { }
}

public class StateMachine : State
{
    private Dictionary<long, State> _states = new Dictionary<long, State>();

    public State? DefaultState { get; protected set; }
    public State? CurrentState { get; protected set; }
    public State? PreviousState { get; protected set; }

    public void Execute()
    {
        if (CurrentState == null)
            OnEnter();

        OnUpdate();
    }

    public override void OnEnter()
    {
        base.OnEnter();

        if (DefaultState != null)
            ForceSetState(DefaultState);
    }

    public override void OnUpdate()
    {
        base.OnUpdate();

        CurrentState?.OnUpdate();
    }

    public override void OnExit()
    {
        base.OnExit();

        CurrentState?.OnExit();
        CurrentState = null;
    }

    public void AddState(State state)
    {
        if (state == null)
            throw new ArgumentNullException(nameof(state));

        Check.IsFalse(_states.ContainsKey(state.Identity), "状态已存在");

        state.OwnerStateMachine = this;
        _states.Add(state.Identity, state);

        if (_states.Count == 1)
            SetDefaultState(state.Identity);
    }

    public void SetDefaultState(long stateIdentity)
    {
        Check.IsTrue(_states.ContainsKey(stateIdentity), "找不到可设置的状态");

        DefaultState = _states[stateIdentity];
    }

    public bool TrySetState(long stateIdentity)
    {
        if (CurrentState != null && CurrentState.Identity == stateIdentity)
            return true;

        Check.IsTrue(_states.ContainsKey(stateIdentity), "找不到可设置的状态");
        return TryResetState(_states[stateIdentity]);
    }

    // 当满足切换状态条件时，进行切换状态操作。
    private bool TryResetState(State state)
    {
        if (!CanSetState(state))
            return false;

        ForceSetState(state);
        return true;
    }

    //验证是否满足切换状态的条件。
    private bool CanSetState(State state)
    {
        if (state == null)
            throw new ArgumentNullException(nameof(state));

        if (CurrentState != null && !CurrentState.CanExitState)
            return false;

        if (state != null && !state.CanEnterState)
            return false;

        return true;
    }

    // 切换状态。
    private void ForceSetState(State state)
    {
        if (state == null)
            throw new ArgumentNullException(nameof(state));

        PreviousState = CurrentState;

        CurrentState?.OnExit();
        CurrentState = state;
        CurrentState.OnEnter();
    }
}